// PaletteView.m
// By Jayson Adams, NeXT Developer Support Team
// You may freely copy, distribute and reuse the code in this example.
// NeXT disclaims any warranty of any kind, expressed or implied, as to its
// fitness for any particular use.
// Modified by Mara Helmuth to accomodate multiple images.

// Unit Generator tiffs are 80w,80h, converters 80x66(overlap height-wise).
// PaletteView contains 18(+2repeated) ug tiffs and 6 converters:
//  Up to release 1.1:
// Oscil   Buzz    Rand   Evp    Reson   	pchcps
//					   			pchoct
// Comb    Pluck   Delay  Reverb Ws	cpspch
// +       	-       	*      	/      	Sound     	cpsoct
//					   			octpch
// Preset  Pfield  Create	 	   		octcps 

//   Release 1.2:
// Oscil  	Buzz	Rand   	Evp    	Reson    	pchcps
//					   					pchoct
// Comb 	Pluck	 		Allpass 	Reverb 	cpspch       delay will be in middle
// +       	-       	*      		/      		WS     	cpsoct
//					   					octpch
// Sound	Pfield  	Value	C-expr	??? 	   	octcps 

#import <math.h>
#import <appkit/NXImage.h>
#import <appkit/Window.h>

#import "TransparentWindow.h"

#import "PaletteView.h"


@implementation PaletteView


/* instance methods */

- (BOOL)acceptsFirstMouse
{
    return YES;
}

- setImages
{
	int num, row, col;
	
  /* setup images */
   image[0] = [NXImage findImageNamed:"Sound"];
   image[1] = [NXImage findImageNamed:"Pfield"];
   image[2] = [NXImage findImageNamed:"Preset"];       // Value
   image[3] = [NXImage findImageNamed:"Cexpr"];       // C expression
   image[4] = [NXImage findImageNamed:"User"];
   image[5] = [NXImage findImageNamed:"Add"];
   image[6] = [NXImage findImageNamed:"Sub"];
   image[7] = [NXImage findImageNamed:"Mult"];
   image[8] = [NXImage findImageNamed:"Div"];
   image[9] = [NXImage findImageNamed:"WS"];
   image[10] = [NXImage findImageNamed:"Comb"];
   image[11] = [NXImage findImageNamed:"Pluck"];
   image[12] = [NXImage findImageNamed:"NotWorking"];     //  Should be Allpass, allpass is delay 
   image[13] = [NXImage findImageNamed:"Allpass"];
   image[14] = [NXImage findImageNamed:"Reverb"];
   image[15] = [NXImage findImageNamed:"Oscil"];
   image[16] = [NXImage findImageNamed:"Buzz"];
   image[17] = [NXImage findImageNamed:"Rand"];
   image[18] = [NXImage findImageNamed:"Evp"];
   image[19] = [NXImage findImageNamed:"Reson"];
   image[20] = [NXImage findImageNamed:"octcps"];
   image[21] = [NXImage findImageNamed:"octpch"];
   image[22] = [NXImage findImageNamed:"cpspch"];
   image[23] = [NXImage findImageNamed:"cpsoct"];
   image[24] = [NXImage findImageNamed:"pchoct"];
   image[25] = [NXImage findImageNamed:"pchcps"];
   num = 0;
   for(row = 0; num < PAL_IMAGES; row++) {
    	for(col = 0; col < COLS; col++) {
 
   /* the hotRect marks the image's bounds */
    		[image[num] getSize:&(hotRect[num].size)];

			hotRect[num].origin.x = col*ICON_SIZE;
    		hotRect[num].origin.y = row*ICON_SIZE;
			num++;
			if(num == PAL_IMAGES)
				break;
	}
    }

// do converter images
    for(row = 0; row < CONV_IMAGES; row++) {
   		[image[num] getSize:&(hotRect[num].size)];

		hotRect[num].origin.x = COLS * ICON_SIZE; // right hand column
    	hotRect[num].origin.y = row*CONV_HEIGHT;
		num++;
    }    
    
    [self display];
    
    return self;
}

- mouseDown:(NXEvent *)theEvent
{
    id		imageWindow;
    NXRect	windowRect;
    NXPoint	hitPoint, offset, mouseLocation;
    int		chosen, midx, midy, row, col;
        
  /* return if not within the image's bounds */
    hitPoint = theEvent->location;
    [self convertPoint:&hitPoint fromView:nil];

	midx = ICON_SIZE*(COLS+1)/2;  
	midy = ICON_SIZE*ROWS/2;
	chosen = -1;
	
	if(hitPoint.x < midx) {			// find the column
		if(hitPoint.x < ICON_SIZE)
			col = 0;
		else if(hitPoint.x < 2*ICON_SIZE)
			col = 1;
		else
			col = 2;
	}
	else {
		if(hitPoint.x < midx+ICON_SIZE)
			col = 3;
		else if(hitPoint.x < ICON_SIZE*5)
			col = 4;
		else
			col = 5;
	}
	if(col == 5) { 					// converter, find row
		if(hitPoint.y < midy) {
			if(hitPoint.y < CONV_HEIGHT) 
				chosen = 20;
			else if(hitPoint.y < CONV_HEIGHT*2)
				chosen = 21;
			else
				chosen = 22;
		}
		else
			if(hitPoint.y < midy+CONV_HEIGHT)
				chosen = 23;
			else if(hitPoint.y < CONV_HEIGHT*5)
				chosen = 24;
			else
				chosen = 25;
	}
	else {							// not a converter ugen, find row
		if(hitPoint.y < midy) {
			if(hitPoint.y < ICON_SIZE)
				row = 0;
			else
				row = 1;
		}
		else {
			if(hitPoint.y < midy+ICON_SIZE)
				row = 2;
			else 
				row = 3;
		}
		chosen = row*5+col;
	}	
	   
      
  // convert the hotRect to screen-based coordinates
    windowRect = hotRect[chosen];				
    dragImage = image[chosen];
	
	[patchVw setUgen:chosen];  // tell PatchView which image
	
    [self convertRect:&windowRect toView:nil];
    [window convertBaseToScreen:&windowRect.origin];
    
    imageWindow = [[TransparentWindow alloc] initForImage:dragImage
					     at:&(windowRect.origin)
					     forView:self];
    
  /* compute the offset from the image's origin to the mouse location */
    	offset.x = hitPoint.x - NX_X(&hotRect[chosen]);
    	offset.y = hitPoint.y - NX_Y(&hotRect[chosen]);
    
  /* convert the mousedown location to screen coordinates */
    mouseLocation = theEvent->location;
    [window convertBaseToScreen:&mouseLocation];
    
  /* go into the dragging loop */
   	[imageWindow dragFromMouseDown:&mouseLocation mouseOffset:&offset];
    
    return self;
}


- drawSelf:(NXRect *)rects :(int)count
{
	int i;
    NXDrawGrayBezel(&bounds, NULL); /* not sure I like this */
    
    for(i = 0; i < PAL_IMAGES+CONV_IMAGES; i++) {
    	[image[i] composite:NX_SOVER toPoint:&hotRect[i].origin];
    }
    
    return self;
}

@end
